package com.yungu.swift.lbs.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.yungu.swift.autoconfig.redis.RedisCacheService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.constants.OrderConstant;
import com.yungu.swift.lbs.model.DriverLocation;
import com.yungu.swift.lbs.model.param.TraceCheckParam;
import com.yungu.swift.lbs.model.param.TrsearchParam;
import com.yungu.swift.lbs.model.vo.DistanceVo;
import com.yungu.swift.lbs.model.vo.DrivingNearestVo;
import com.yungu.swift.lbs.model.vo.TrackVo;
import com.yungu.swift.lbs.service.DistanceService;
import com.yungu.swift.lbs.trace.baidu.util.BaiduTraceUtils;
import com.yungu.swift.lbs.trace.gaode.TerminalUtils;
import com.yungu.swift.lbs.trace.gaode.TraceUtils;
import com.yungu.swift.lbs.utils.LocationUtils;
import com.yungu.swift.utils.HttpUtils;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.MapUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

import static com.yungu.swift.lbs.config.NacosListener.THIRDPARTY_CONFIG;

/**
 * @author : cuixiuyin
 * @date : 2019/4/9
 */
@Slf4j
@Service
public class DistanceServiceImpl implements DistanceService {

    @Autowired
    private RedisCacheService redisCacheService;
    @Autowired
    private MongoOperations mongoOperations;

    @Override
    public ResponseData<Double> distanceForBaiduTrace(String entityName, long startTime, long endTime) {
        return ResponseData.buildSuccessResponse(BaiduTraceUtils.getDistanceDefault(entityName, startTime, endTime));
    }

    @Override
    public ResponseData<Map<String, Object>> baiduTraceCheck(List<TraceCheckParam> list) {
        String baiduAk = THIRDPARTY_CONFIG.getBaiduAK();
        if (baiduAk == null || CollectionUtils.isEmpty(list)) {
            return ResponseData.buildSuccessResponse(MapUtils.build());
        }
        List<Map<String, Object>> paramList = new ArrayList();
        for (TraceCheckParam checkParam : list) {
            Map<String, Object> locationsMap = new HashMap<>();
            locationsMap.put("latitude", checkParam.getLatitude());
            locationsMap.put("longitude", checkParam.getLongitude());
            locationsMap.put("coord_type_input", checkParam.getCoordTypeInput());
            locationsMap.put("loc_time", checkParam.getLocTime().getTime() / 1000);
            paramList.add(locationsMap);

        }
        //将轨迹点json作为参数调用百度纠偏接口 返回纠偏后的数据
        Map<String, Object> paramMap = new HashMap<>(16);
        try {
            paramMap.put("point_list", JsonUtils.writeJsonStr(paramList));
            paramMap.put("ak", baiduAk);
            paramMap.put("coord_type_output", "gcj02");
            paramMap.put("coord_type_output", "gcj02&rectify_option=need_mapmatch:1|transport_mode:auto|denoise_grade:1|vacuate_grade:1");
            String responseString = HttpUtils.postResponseString("http://api.map.baidu.com/rectify/v1/track", paramMap);
            return ResponseData.buildSuccessResponse(JsonUtils.readValue(responseString, Map.class));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseData.buildSuccessResponse(MapUtils.build());
    }

    @Override
    public ResponseData<DrivingNearestVo> getDrivingNearest(String originLng, String originLat, String areaLng, String areaLat) {
        DrivingNearestVo drivingNearestVO = new DrivingNearestVo();
        Map<String, Object> objectMap = LocationUtils.getDriving(originLng, originLat, areaLng, areaLat);
        if (objectMap != null) {
            Object distance = objectMap.get("distance");
            Object duration = objectMap.get("duration");
            drivingNearestVO.setDistance(distance == null ? 0D : Double.parseDouble(distance.toString()));
            drivingNearestVO.setDuration(duration == null ? 0 : Integer.parseInt(duration.toString()));
        }
        return ResponseData.buildSuccessResponse(drivingNearestVO);
    }


    @Override
    public ResponseData<List<TrackVo>> gaodeTraceCheck(String driverUuid, String orderUuid, TrsearchParam trsearchParam) {
        String key = THIRDPARTY_CONFIG.getGaodeKey();
        String sid = THIRDPARTY_CONFIG.getGaodeSid();
        // 终端id
        Long tid;
        String tName = "driver_" + driverUuid;
        Object obj = redisCacheService.get(tName);
        if (obj != null) {
            tid = Long.parseLong(obj.toString());
        } else {
            List<TerminalUtils.TerminalInfo> list = TerminalUtils.listTerminal(key, sid, null, tName, null);
            if (CollectionUtils.isNotEmpty(list)) {
                TerminalUtils.TerminalInfo terminalInfo = list.get(0);
                tid = terminalInfo.getTid();
                redisCacheService.set(tName, tid, 10L);
            } else {
                // 创建终端
                tid = TerminalUtils.createTerminal(key, sid, tName);
                redisCacheService.set(tName, tid, 10L);
            }
        }
        log.info("616161616616：{}", obj);
        // 轨迹id
        Long trid = null;
        Criteria criteria = Criteria.where("orderUuid").is(orderUuid);
        criteria.and("orderStatus").is(OrderConstant.ORDER_STATUS_START);
        Query query = new Query(criteria);
        DriverLocation driverLocation = mongoOperations.findOne(query, DriverLocation.class);
        if (driverLocation != null && driverLocation.getTrid() != null) {
            trid = Long.parseLong(driverLocation.getTrid());
        }
        if (trid == null) {
            log.info("订单：{}，还未上传轨迹点", orderUuid);
            return ResponseData.buildSuccessResponse(Lists.newArrayList());
        }
        return ResponseData.buildSuccessResponse(trsearch(key, sid, tid, trid, trsearchParam, Lists.newArrayList()));
    }

    @Override
    public ResponseData<Double> getDistance(Double lng1, Double lat1, Double lng2, Double lat2) {
        return ResponseData.buildSuccessResponse("获取计算结果", LocationUtils.getDistance(lng1, lat1, lng2, lat2));
    }

    @Override
    public ResponseData<List<DistanceVo>> getDistance(String origins, String destination) {
        try {
            StringBuffer buffer = new StringBuffer("http://restapi.amap.com/v3/distance")
                    .append("?key").append("=").append(THIRDPARTY_CONFIG.getGaodeKey())
                    .append("&origins").append("=").append(URLEncoder.encode(origins, "UTF-8"))
                    .append("&destination").append("=").append(destination)
                    .append("&type").append("=").append(1)
                    .append("&output").append("=").append("JSON");
            String resultStr = HttpUtils.getResponseString(buffer.toString());
            JsonNode jsonObject = JsonUtils.readNode(resultStr);
            String status = jsonObject.get("status").asText();
            String info = jsonObject.get("info").asText();
            if ("1".equals(status) && "OK".equals(info)) {
                ArrayNode results = JsonUtils.readArray(jsonObject.get("results").toString());
                List<DistanceVo> result = new LinkedList<>();
                for (JsonNode jsonNode : results) {
                    DistanceVo distanceVo = new DistanceVo();
                    distanceVo.setOriginId(jsonNode.get("origin_id").asInt());
                    distanceVo.setDestId(jsonNode.get("dest_id").asInt());
                    distanceVo.setDistance(jsonNode.get("distance").asInt());
                    distanceVo.setDuration(jsonNode.get("duration").asInt());
                    result.add(distanceVo);
                }
                return ResponseData.buildSuccessResponse(result);
            }
        } catch (IOException e) {
            log.error("getDistance readNode error", e);
        }
        return ResponseData.buildSuccessResponse(Lists.newArrayList());
    }

    /**
     * 递归查询全部的点数量
     *
     * @param key
     * @param sid
     * @param tid
     * @param trid
     * @param trsearchParam
     * @param result
     * @return
     */
    private List<TrackVo> trsearch(String key, String sid, Long tid, Long trid, TrsearchParam trsearchParam,
                                   List<TrackVo> result) {
        if (trsearchParam == null) {
            trsearchParam = new TrsearchParam();
        }
        List<TrackVo> trackVos = TraceUtils.trsearch(key, sid, tid, trid, trsearchParam);
        result.addAll(trackVos);
        if ((trsearchParam.getPage() * trsearchParam.getPagesize()) > result.size()) {
            return result;
        } else {
            trsearchParam.setPage(trsearchParam.getPage() + 1);
            trsearch(key, sid, tid, trid, trsearchParam, result);
        }
        return result;
    }

    @Override
    public ResponseData<List<Double>> getBatchDistance(String originLngLat, List<String> destLngLatList) {
        List<Double> result = new ArrayList<>();
        try {
            //批量请求地址URL
            ArrayNode urlJsonArray = JsonUtils.newArrayNode();
            for (String destLnglat : destLngLatList) {
                ObjectNode urlJson = JsonUtils.newJsonNode();
                StringBuilder url = new StringBuilder();
                url.append("/v3/distance?");
                url.append("origins=").append(originLngLat);
                url.append("&destination=").append(destLnglat);
                url.append("&output=json&key=").append(THIRDPARTY_CONFIG.getGaodeKey());
                urlJson.put("url", url.toString());
                urlJsonArray.add(urlJson);
            }

            ObjectNode batchUrlJson = JsonUtils.newJsonNode();
            batchUrlJson.set("ops", urlJsonArray);

            Map<String, Object> postResultMap = HttpUtils.post("https://restapi.amap.com/v3/batch?key=" +
                    THIRDPARTY_CONFIG.getGaodeKey(), HttpUtils.ENTITY_TYPE_JSON, MapUtils.build("_JSON_STRING",
                    batchUrlJson.toString()), new HashMap<>(2));
            ArrayNode arrayNode = JsonUtils.readValue(postResultMap.get("result").toString(), ArrayNode.class);
            if (arrayNode.size() > 0) {
                for (int i = 0; i < arrayNode.size(); i++) {
                    JsonNode jsonNode = arrayNode.get(i);
                    if (jsonNode.get("status").asInt() == 200) {
                        result.add(jsonNode.get("body").get("results").get(0).get("distance").asDouble());
                    } else {
                        result.add(0D);
                    }
                }
            }
        } catch (Exception e) {
            log.error("getBatchDistance readNode error", e);
        }
        return ResponseData.buildSuccessResponse(result);
    }
}
